﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using Mindfor.Web.Models;
using Mindfor.Web.Data;
using NHibernate.Linq;

namespace Mindfor.Web.Modules.System.Controllers
{
	/// <summary>
	/// Defines actions to render menus.
	/// </summary>
	public class MenuController : CmsController
	{
		/// <summary>
		/// Returns MainMenu view result with root links.
		/// </summary>
		[ChildActionOnly]
		public ActionResult MainMenu()
		{
			ViewData.Model = GetMenuLinks(null);
			return PartialView();
		}

		/// <summary>
		/// Returns SubMenu view result with root links.
		/// </summary>
		[ChildActionOnly]
		public ActionResult SubMenu()
		{
			if (CurrentPage == null)
				return null;
			ViewData.Model = GetMenuLinks(CurrentPage);
			return PartialView();
		}

		/// <summary>
		/// Renders management menu.
		/// </summary>
		[CmsAuthorize]
		[ChildActionOnly]
		public ActionResult AdminMenu()
		{
			List<AdminLink> links = new List<AdminLink>();
			foreach (var item in GetAdminLinks())
			{
				CmsAuthorizeAttribute cmsAuthAttr = item.Item3.GetCmsAuthorizeAttribute();
				if (cmsAuthAttr == null || cmsAuthAttr.HasAccess(User))
				{
					string url = Url.ActionModule(item.Item3.ActionName, item.Item3.ControllerDescriptor.ControllerName, item.Item2);
					links.Add(new AdminLink(item.Item1.Title, url, item.Item1.Category));
				}
			}
			return PartialView(links);
		}

		/// <summary>
		/// Generates links for child pages.
		/// </summary>
		/// <param name="parentPage">Page to get child pages of. If null then links generated for root pages.</param>
		private List<Link> GetMenuLinks(Page parentPage)
		{
			IQueryable<Page> levelPages = parentPage != null ? 
				(IQueryable<Page>)parentPage.ChildPages :
				Data.Query<Page>().GetRootPages();

			List<Page> pages = levelPages
				.Where(r => r.ShowInMenu)
				.OrderBy(r => r.Sort)
				.ToList()
				.Where(r => r.HasAccess(User))
				.ToList();

			List<Link> links = new List<Link>();
			foreach (Page p in pages)
			{
				PageText pt = p.GetText(Language);
				if (pt != null)
				{
					Link l = new Link
					{
						Text = !String.IsNullOrEmpty(pt.MenuTitle) ? pt.MenuTitle : pt.Title,
						Url = !String.IsNullOrEmpty(pt.Url) ? pt.Url : Url.Page(p.Id),
						Selected = CurrentPage != null && CurrentPage.Id == p.Id
					};
					if (p.OpenInNewWindow)
						l.Target = "_blank";
					links.Add(l);
				}
			}
			return links;
		}

		#region Static members

		static List<global::System.Tuple<AdminLinkAttribute, string, ActionDescriptor>> s_adminLinkAttibutes = null;
		static object s_manageLinksBlockObject = new object();
		
		/// <summary>
		/// Collects all ManageLinkAttributes through all enabled modules.
		/// </summary>
		public static List<global::System.Tuple<AdminLinkAttribute, string, ActionDescriptor>> GetAdminLinks()
		{
			lock (s_manageLinksBlockObject)
			{
				// collect all manage links
				if (s_adminLinkAttibutes == null)
				{
					s_adminLinkAttibutes = new List<global::System.Tuple<AdminLinkAttribute, string, ActionDescriptor>>();
					foreach (ModuleBase module in ModuleFactory.Default.Modules.GetRegisteredModules())
					{
						foreach (ControllerDescriptor controller in module.GetControllers())
						{
							foreach (ActionDescriptor action in controller.GetCanonicalActions())
							{
								AdminLinkAttribute attr = action.GetCustomAttribute<AdminLinkAttribute>(true);
								if (attr != null)
									s_adminLinkAttibutes.Add(new global::System.Tuple<AdminLinkAttribute, string, ActionDescriptor>(attr, module.Name, action));
							}
						}
					}
				}

				return s_adminLinkAttibutes;
			}
		}

		#endregion
	}
}
